package com.sitech.ibnms.c3p.quartz;

import com.sitech.ibnms.c3p.domain.CronScheduleJob;
import com.sitech.ibnms.c3p.service.C3pScheduleService;
import com.sitech.ibnms.c3p.util.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

import static com.sitech.ibnms.c3p.Application.sneakyThrow;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * Created by liujhc on 7/23.
 * 其中第二个服务，增加一个调度 或停止调度  这个方法 为
 * 与
 */
@Component
public class C3pScheduleServiceImpl implements C3pScheduleService {
    private Logger logger = LoggerFactory.getLogger(C3pScheduleServiceImpl.class);
    @Resource(name = "quartzScheduler")
    private Scheduler scheduler;
    @Resource(name = "c3pTaskStartingJob")
    private JobDetail c3pTaskStartingJob;
    @Resource(name = "multiC3pTaskScheduleJob")
    private JobDetail multiC3pTaskScheduleJob;
    private static final String TRIGGER_GROUP = "TASK_STARTING";

    @Override
    public String scheduleTask(String taskId, String userId, String cronExpression) {
        CronScheduleJob cronScheduleJob = new CronScheduleJob();
        cronScheduleJob.setTaskId(taskId);
        cronScheduleJob.setUserId(userId);
        cronScheduleJob.setCronExpression(cronExpression);
        return scheduleTask(cronScheduleJob);
    }

    @Override
    public String scheduleTask(CronScheduleJob setting) {
        logger.info("scheduleTask: {}", JSONUtil.toJSON(setting));

        Assert.notNull(setting.getTaskId(), "CronScheduleJob.taskId must not be null");
        Assert.notNull(setting.getUserId(), "CronScheduleJob.userId must not be null");
        Assert.notNull(setting.getCronExpression(), "CronScheduleJob.cronExpression must not be null");

        String scheduleId = setting.getScheduleId();
        if (StringUtils.isEmpty(scheduleId)) {
            scheduleId = JobKey.createUniqueName(TRIGGER_GROUP);
        }
        logger.info("scheduleId is {}", scheduleId);

        Trigger trigger = newTrigger()
                .withIdentity(scheduleId, TRIGGER_GROUP)
                .withSchedule(cronSchedule(setting.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing())
                .forJob(c3pTaskStartingJob)
                .usingJobData(StartC3pTaskJob.C3P_TASK_ID, setting.getTaskId())
                .usingJobData(StartC3pTaskJob.USER_ID, setting.getUserId())
                .usingJobData(StartC3pTaskJob.TASK_TITLE, "【自动调度任务】")
                .build();
        try {
            scheduler.scheduleJob(trigger);
        } catch (SchedulerException e) {
            throw sneakyThrow(e);
        }
        return scheduleId;
    }

    @Override
    public String scheduleTasksSecondsDelay(String cronExpression, String userId, Pair<Integer, String>... tasks) {
        Assert.notNull(cronExpression, "cronExpression must not null");
        Assert.notNull(userId, "userId must not null");
        Assert.notEmpty(tasks, "tasks must not empty");

        List<Pair<Integer, String>> taskList = Arrays.asList(tasks);
        logger.info("scheduleTasksSecondsDelay: cronExpression={}, userId={}, tasks={}", cronExpression, userId, taskList);

        for (Pair<Integer, String> task : tasks) {
            Assert.noNullElements(new Object[]{task.getLeft(), task.getRight()});
        }

        String scheduleId = JobKey.createUniqueName(TRIGGER_GROUP);
        logger.info("scheduleId is {}", scheduleId);
        Trigger trigger = newTrigger().withIdentity(scheduleId, TRIGGER_GROUP)
                .withSchedule(cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing())
                .forJob(multiC3pTaskScheduleJob)
                .usingJobData(StartMultiC3pTasksJob.USER_ID, userId)
                .build();
        trigger.getJobDataMap().put(StartMultiC3pTasksJob.TASK_LIST, taskList);
        try {
            scheduler.scheduleJob(trigger);
        } catch (SchedulerException e) {
            throw sneakyThrow(e);
        }
        return scheduleId;
    }

    @Override
    public boolean unscheduleTask(String... scheduleIds) {
        logger.info("deleteSchedule: {}", JSONUtil.toJSON(scheduleIds));
        boolean allDeleted = true;
        try {
            if (scheduleIds != null) {
                for (String scheduleId : scheduleIds) {
                    allDeleted = allDeleted && scheduler.unscheduleJob(TriggerKey.triggerKey(scheduleId, TRIGGER_GROUP));
                }
            }
        } catch (SchedulerException e) {
            throw sneakyThrow(e);
        }
        return allDeleted;
    }

    @Override
    public boolean checkExists(String scheduleId) {
        try {
            return scheduler.checkExists(TriggerKey.triggerKey(scheduleId, TRIGGER_GROUP));
        } catch (SchedulerException e) {
            throw sneakyThrow(e);
        }
    }
}
